/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package MetricsRetriever.RetrieverComponents;

import DataStructures.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import DataStructures.ProjectInformation;
import General.Globals;
import General.RequestMaker;
import java.io.ByteArrayInputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.w3c.dom.NodeList;

/**
 *
 * @author Manuel
 */
public class SFParser extends Parser{


    private String xmlLink;
    private String xmlData;
    private ProjectInformation data;
    private String groupID;

    public SFParser(){
    }

    public ProjectInformation getProjectInformation(String link){
        data = new ProjectInformation();
        data.setUrl(link);
        data.setForge(Globals.SOURCEFORGE);
        data.setName(this.parseCharacterData("projects/","/",link,false,true));;
        xmlLink = "http://sourceforge.net/api/project/name/"+data.getName()+"/doap";
        xmlData = RequestMaker.getPage(xmlLink);
        this.retrieveArchieveLink();
        this.retrieveActivityLevel();
        this.parse();
        return data;
    }


    public void parse(){
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(new ByteArrayInputStream(xmlData.getBytes()));
            traverse(document.getDocumentElement(), 0);
        } catch (Exception ex) {

            System.out.println("Could not parse the following xml String"+xmlData);
        }
    }

    private void traverse(Node n, int level) {

        int i;
        // find out what type of node this is and call the corresponding method

        short t = n.getNodeType();
        if (t == Document.ELEMENT_NODE) {
                this.handleItem(n);

            NodeList nl = n.getChildNodes();
            if (nl.getLength() == 0) {
                return;
            }

            for (i = 0; i < nl.getLength(); i++) {
                traverse(nl.item(i), level + 1);
            }
        }
        if (t == Document.ELEMENT_NODE) {
            //END NODE
        }
    }

    private void handleItem(Node itemNode){
        Bug currentBug = new Bug();
        NodeList nl = itemNode.getChildNodes();

        for (int i = 0; i < nl.getLength(); i++) {
            Node currentNode = nl.item(i);

            //parse the description
            if(currentNode.getNodeName().equals("description")){
                data.setDescription(this.filterHtml(currentNode.getTextContent()));
            }


            //parse the repository link date
            else if(currentNode.getNodeName().toLowerCase().contains("anon")){
                String value = currentNode.getTextContent();
                if(value.contains("cvs")){
                    if(data.getRepositoryLink() == null || !data.getRepositoryLink().contains("svn")){
                        data.setRepositoryLink(value);
                        data.setRepositoryType(Globals.CVS);
                    }
                }
                else if(value.contains("svn")){
                    String val = value;
                    if(!(value.toLowerCase().endsWith("trunk/") || value.toLowerCase().endsWith("trunk"))){
                        if(value.endsWith("/"))
                            val = val+"trunk";
                        else
                            val = val+"/trunk";
                    }
                    data.setRepositoryLink(val);
                    data.setRepositoryType(Globals.SVN);
                }
            }

            //parse the programming languages
            else if(currentNode.getNodeName().toLowerCase().contains("programming-language")){
                String value = currentNode.getTextContent().toLowerCase();
                if(value.contains("java"))
                    data.addLanguage(value);
                else if (value.contains("c++"))
                    data.addLanguage("cplusplus");
            }

            //parse the collaborators
            else if(currentNode.getNodeName().toLowerCase().contains("foaf:nick")){
                String value = currentNode.getTextContent().toLowerCase();
                String grandFatherNode = currentNode.getParentNode().getParentNode().getNodeName().toLowerCase();
                if(grandFatherNode.contains("developer")||grandFatherNode.contains("maintainer")){
                    String alternative = currentNode.getParentNode().getFirstChild().getTextContent();
                    data.addCollaboratorIfNew(value,alternative);
                }
            }

            //parse the labels
            else if(currentNode.getNodeName().toLowerCase().contains("sf:topic") || currentNode.getNodeName().toLowerCase().contains("audience")){
                String value = currentNode.getTextContent().toLowerCase();
                data.addLabel(value);
            }

            //retrieve bugtracker link
            else if(currentNode.getNodeName().toLowerCase().contains("rss:channel")){
                if(currentNode.getParentNode().getParentNode().getNodeName().toLowerCase().contains("bug-database") && currentNode.getParentNode().getChildNodes().item(1).getTextContent().toLowerCase().contains("bug")){
                    String link = currentNode.getAttributes().getNamedItem("rdf:resource").getTextContent();
                    data.setBugLink(link);
                    data.setBugTracker(Globals.SFBUGTRACKER);
                }
            }

            //retrieve ID
            else if(currentNode.getNodeName().toLowerCase().contains("sf:id")){
                this.groupID = currentNode.getTextContent();
            }



        }
    }

    private String handleCDATA(Node currentNode) {
        Node childNode = currentNode.getFirstChild();
        if(childNode.getNodeType() == Document.CDATA_SECTION_NODE)
            return childNode.getNodeValue();
        else return "";
    }

    private void retrieveArchieveLink() {
        //TODO implement
        ProjectPackage pkg = new ProjectPackage();

        //retrieve the package name
        String downloadsPage = RequestMaker.getPage(data.getUrl()+"files");
        String area = this.parseCharacterData("Looking for the latest version?", "class=", downloadsPage, false, true);
        String link = this.parseCharacterData("href=\"", "\"", area, false, true);

        if(link.endsWith("/download"))
            link = link.substring(0,link.lastIndexOf("/"));

        boolean isInterestingLink =  link.endsWith(".tar.bzip2") || link.endsWith(".tbz2") || link.endsWith(".tar.bz2") || link.endsWith(".tar.gzip") || link.endsWith(".tgz") || link.endsWith(".tar.gz") || link.endsWith("zip") || link.endsWith(".tar") || link.endsWith(".jar") || link.endsWith(".class");
        if(link == null || link.isEmpty() || !isInterestingLink)
            return;
        pkg.setName(link);

        //retrieve the date of upload
        String date = parseCharacterData("released on ", " ", area, false, true);
        DateFormat df = DateFormat.getDateInstance();
        Date myDate = new Date();
        if(date.contains("-")){
            myDate.setYear(Integer.parseInt(date.substring(0,date.indexOf("-")))-1900);
            myDate.setMonth(Integer.parseInt(date.substring(date.indexOf("-")+1,date.lastIndexOf("-"))));
            myDate.setDate(Integer.parseInt(date.substring(date.lastIndexOf("-")+1)));
            pkg.setDate(myDate);
        }
        DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
        if(link == null || link.isEmpty())
            return;
        else
            data.setArchieveLink(pkg);

    }

    private void retrieveActivityLevel() {
        String appendix = "";
        if(data.getRepositoryType() == Globals.SVN)
            appendix = "&type=svn&mode=60day";
        if(data.getRepositoryType() == Globals.CVS)
            appendix = "&type=cvs&mode=60day";

        String statURL = "http://sourceforge.net/project/stats/detail.php?group_id="+this.groupID+"&ugn="+data.getName()+appendix;
        String statPage = RequestMaker.getPage(statURL);
        String statNumber = this.parseCharacterData("<td>Total</td>", "</tr>", statPage, false, true);
        if(statNumber.isEmpty()){
            data.setActivity(0);
            return;
        }
        while(statNumber.contains("<td>")){
            statNumber = statNumber.substring(statNumber.indexOf("<td>")+"<td>".length());
        }
        statNumber = this.filterHtml(statNumber);
        statNumber = statNumber.replaceAll(" ","");
        statNumber = statNumber.replaceAll(",","");
        int stats = Integer.parseInt(statNumber);
        if(stats == 0)
            data.setActivity(0);
        else if(stats < 5)
            data.setActivity(1);
        else if(stats < 30)
            data.setActivity(2);
        else
            data.setActivity(3);
    }

}